﻿// (c) Copyright Fernando Cerqueira.
// This source is subject to the Microsoft Public License (Ms-PL).
// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.

using System;
using System.Reflection;
using EnvDTE80;
using Microsoft.VisualStudio.CommandBars;
using Microsoft.VisualStudio.Shell.Interop;
using EnvDTE;
using System.Xml.XPath;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using VirtualMachines;
using AppConst = WindowsPhoneCommands.Constants;
using Appres = WindowsPhoneCommands.Resources;
using Microsoft.VisualStudio;

// ReSharper disable CheckNamespace
namespace WindowsPhoneCommands
// ReSharper restore CheckNamespace
{
    internal static class EnvPhoneDevice
    {
        internal static ProjectItem FolderExistProject(Project project,string nameFolder)
        {
            var directoryInfo = new FileInfo(project.FullName).Directory;
            var root = String.Empty;
            if (directoryInfo != null)
            {
                root = directoryInfo.FullName + "\\";
            }
            var enumprjs = project.ProjectItems.GetEnumerator();
            while (enumprjs.MoveNext())
            {
                var cur = (ProjectItem)enumprjs.Current;
                if (cur.Kind == EnvDTE.Constants.vsProjectItemKindPhysicalFolder)
                {
                    if (cur.Name.ToLower() == nameFolder.ToLower())
                    {
                        return cur;
                    }
                }
                if (cur.ProjectItems != null)
                {
                    var result =  GetExistsubfoldersProject(root,nameFolder,cur.ProjectItems);
                    if (result != null)
                    {
                        return result;
                    }
                }
            }
            return null;
        }

        private static ProjectItem GetExistsubfoldersProject(string root,string nameFolder, ProjectItems item)
        {
            var enumprjs = item.GetEnumerator();
            while (enumprjs.MoveNext())
            {
                var cur = (ProjectItem)enumprjs.Current;
                if (cur.Kind == EnvDTE.Constants.vsProjectItemKindPhysicalFolder)
                {
                    var localpath = ((ProjectItem)enumprjs.Current).Properties.Item("LocalPath").Value.ToString().Replace(root,"");
                    if (localpath.EndsWith("\\"))
                    {
                        localpath = localpath.Substring(0, localpath.Length - 1);
                    }
                    if (localpath.ToLower() == nameFolder.ToLower())
                    {
                        return cur;
                    }
                }
                if (cur.ProjectItems != null)
                {
                    var result = GetExistsubfoldersProject(root,nameFolder, cur.ProjectItems);
                    if (result != null)
                    {
                        return result;
                    }
                }
            }
            return null;
        }

        internal static IEnumerable<string> GetListFolderFromProject(Project project)
        {
            var result = new List<string>();
            var enumprjs = project.ProjectItems.GetEnumerator();
            var directoryInfo = new FileInfo(project.FullName).Directory;
            var root = String.Empty;
            if (directoryInfo != null)
            {
                root = directoryInfo.FullName + "\\";
            }
            while (enumprjs.MoveNext())
            {
                var cur = (ProjectItem)enumprjs.Current;
                if (cur.Kind ==  EnvDTE.Constants.vsProjectItemKindPhysicalFolder)
                {
                    var localpath = ((ProjectItem)enumprjs.Current).Properties.Item("LocalPath").Value.ToString();
                    if (localpath.EndsWith("\\"))
                    {
                        localpath = localpath.Substring(0, localpath.Length - 1);
                    }
                    result.Add(localpath.Replace(root, ""));
                    if (cur.ProjectItems != null)
                    {
                        result.AddRange(Getsubfolders(root, cur.ProjectItems));
                    }
                }
            }
            return result;
        }

        private static IEnumerable<string> Getsubfolders(string root, ProjectItems item)
        {
            var result = new List<string>();
            var enumprjs = item.GetEnumerator();
            while (enumprjs.MoveNext())
            {
                var cur = (ProjectItem)enumprjs.Current;
                if (cur.Kind ==  EnvDTE.Constants.vsProjectItemKindPhysicalFolder)
                {
                    var localpath = ((ProjectItem)enumprjs.Current).Properties.Item("LocalPath").Value.ToString();
                    if (localpath.EndsWith("\\"))
                    {
                        localpath = localpath.Substring(0, localpath.Length - 1);
                    }
                    result.Add(localpath.Replace(root, ""));
                }
                if (cur.ProjectItems != null)
                {
                    result.AddRange(Getsubfolders(root, cur.ProjectItems));
                }
            }
            return result.ToArray();
        }

        internal static IEnumerable<string> GetListNeutralResourcesFromProject(Project project)
        {
            var res = GetListFilesFromProject(project, new[] {".resx"});
            //remove resource languages
            var keys = PhoneLanguageSupport().Keys;
            var toremove = res.Where(file => keys.Any(key => file.ToLower().EndsWith("." + key.ToLower() + ".resx"))).ToList();
            foreach (var item in toremove)
            {
                res.Remove(item);
            }
            toremove.Clear();
            toremove.AddRange(res.Where(file => keys.Any(key => file.ToLower().EndsWith("." + key.ToLower().Substring(0, 2) + ".resx"))));
            foreach (var item in toremove)
            {
                res.Remove(item);
            }
            return res;
        }

        private static List<string> GetListFilesFromProject(Project project, string[] extensions)
        {
            var result = new List<string>();
            var enumprjs = project.ProjectItems.GetEnumerator();
            var directoryInfo = new FileInfo(project.FullName).Directory;
            var root = String.Empty;
            if (directoryInfo != null)
            {
                root = directoryInfo.FullName + "\\";
            }
            while (enumprjs.MoveNext())
            {
                try
                {
                    var fileextension = ((ProjectItem)enumprjs.Current).Properties.Item("Extension").Value.ToString().ToUpper();
                    if (extensions.Any(extfind => fileextension.ToUpper() == extfind.ToUpper()))
                    {
                        var localpath = ((ProjectItem)enumprjs.Current).Properties.Item("LocalPath").Value.ToString();
                        result.Add(localpath.Replace(root, ""));
                    }
                }
                // ReSharper disable EmptyGeneralCatchClause
                catch
                // ReSharper restore EmptyGeneralCatchClause
                {
                }
                if (((ProjectItem)enumprjs.Current).ProjectItems != null)
                {
                    result.AddRange(GetsubItemImages(root, extensions, ((ProjectItem)enumprjs.Current).ProjectItems));
                }
            }
            return result;
        }

        private static IEnumerable<string> GetsubItemImages(string root, string[] extensions, ProjectItems item)
        {
            var result = new List<string>();
            var enumprjs = item.GetEnumerator();
            while (enumprjs.MoveNext())
            {
                try
                {
                    var fileextension = ((ProjectItem)enumprjs.Current).Properties.Item("Extension").Value.ToString().ToUpper();
                    if (extensions.Any(extfind => fileextension.ToUpper() == extfind.ToUpper()))
                    {
                        var localpath = ((ProjectItem)enumprjs.Current).Properties.Item("LocalPath").Value.ToString();
                        result.Add(localpath.Replace(root, ""));
                    }
                }
                // ReSharper disable EmptyGeneralCatchClause
                catch
                // ReSharper restore EmptyGeneralCatchClause
                {
                }
                if (((ProjectItem)enumprjs.Current).ProjectItems != null)
                {
                    result.AddRange(GetsubItemImages(root, extensions, ((ProjectItem)enumprjs.Current).ProjectItems));
                }
            }
            return result.ToArray();
        }

        internal static void UpdateCacheApp(string name, string alias, string guid)
        {
            var item = WpIsolateSaveData.Current.WpApplication.FirstOrDefault(a => a.Guid == guid);
            if (item != null)
            {
                item.Title = name;
                item.RenameTitle = alias;
            }
            else
            {
                item = new WpDeployApplication { Guid = guid, Title = name, RenameTitle = alias };
            }
            WpIsolateSaveData.Current.AddData(item);
        }

        internal static WmAppManifest ReadWmAppManifest(DTE2 dte, string name)
        {
            var proj = FindProjectByName(dte, name);
            if (proj != null)
            {
                var path = GetPathFileManifest(proj);
                if (!string.IsNullOrEmpty(path))
                {
                    try
                    {
                        //var memStr = new MemoryStream(Encoding.UTF8.GetBytes(path));
                        var xpathDoc = new XPathDocument(path);
                        //memStr.Close();
                        var navigator = xpathDoc.CreateNavigator().SelectSingleNode("//App");
                        if (navigator != null)
                        {
                            // ReSharper disable UseObjectOrCollectionInitializer
                            var result = new WmAppManifest();
                            // ReSharper restore UseObjectOrCollectionInitializer
                            result.Title = Common.XmlUnescape(navigator.GetAttribute("Title", string.Empty).Trim());
                            result.ProductId = Common.XmlUnescape(navigator.GetAttribute("ProductID", string.Empty).Replace("{", "").Replace("}", "").Trim());
                            return result;
                        }
                    }
                    catch
                    {
                        return null;
                    }
                }
            }
            return null;
        }

        internal static string CurrentTargetDevice(WindowsPhone device)
        {
            return device!= null ? device.Name : string.Empty;
        }

        internal static string CurrentEnvDeviceSelected(DTE2 dte)
        {
            foreach (var cmd in from CommandBar commandBar in (_CommandBars)dte.CommandBars from cmd in commandBar.Controls.Cast<object>().OfType<CommandBarPopup>().Where(cmd => cmd.accName[Missing.Value] == "Debug Target") select cmd)
            {
                return cmd.Controls.Count > 0 ? cmd.Controls[1].Caption : string.Empty;
            }
            return String.Empty;
        }


        internal static string PhoneVersion(WindowsPhone device)
        {
                if (device != null)
                {
                    if (device.Connected)
                    {
                        return Appres.Version + "(" + new Version(device.OsMajor, device.OsMinor) + ")";
                    }
                }
                return string.Empty;
        }

        private const string DefaultnameManifestWp = "WMAppManifest.xml";


        private static ProjectItem GetManifestWp(ProjectItem item)
        {
            if (item.Name.ToLower().Contains(DefaultnameManifestWp.ToLower()))
            {
                return item;
            }
            if (item.ProjectItems == null)
            {
                return null;
            }
            var subitems = item.ProjectItems.GetEnumerator();
            while (subitems.MoveNext())
            {
                var result = GetManifestWp((ProjectItem)subitems.Current);
                if (result != null)
                {
                    return result;
                }
            }
            return null;
        }

        private static string GetPathFileManifest(Project project)
        {
            var result = GetProjectManifestWp(project);
            return result != null ? result.Properties.Item("FullPath").Value.ToString() : null;
        }

        internal static string GetNeutralResourcesLanguage(Project project)
        {
            return project.Properties.Item("NeutralResourcesLanguage").Value.ToString();
        }

        internal static string GetValuePhoneLanguageSupport(string key)
        {
            if (key == null) return null;
            return PhoneLanguageSupport().ContainsKey(key) ? PhoneLanguageSupport()[key] : null;
        }

        internal static string GetKeyPhoneLanguageSupport(string value)
        {
            var tmp = PhoneLanguageSupport().FirstOrDefault(l => l.Value == value);
            return tmp.Value == value?tmp.Key:null;
        }

        private static Dictionary<string, string> _phoneLanguageSupport;
        internal static Dictionary<string,string> PhoneLanguageSupport()
        {
            return _phoneLanguageSupport ?? (_phoneLanguageSupport = new Dictionary<string, string>
                    {
                        {"zh-CN",Appres.LngzhCN},
                        {"zh-TW", Appres.LngzhTW},
                        {"cs-CZ", Appres.LngcsCZ},
                        {"da-DK", Appres.LngDaDK},
                        {"nl-NL", Appres.LngnlNL},
                        {"en-US", Appres.LngenUS},
                        {"en-GB", Appres.LngenGB},
                        {"fi-FI", Appres.LngfiFI},
                        {"fr-FR", Appres.LngfrFR},
                        {"de-DE", Appres.LngdeDE},
                        {"el-GR", Appres.LngelGR},
                        {"hu-HU", Appres.LnghuHU},
                        {"id-ID", Appres.LngidID},
                        {"it-IT", Appres.LngitIT},
                        {"ja-JP", Appres.LngjaJP},
                        {"ko-KR", Appres.LngkoKR},
                        {"ms-MY", Appres.LngmsMY},
                        {"nb-NO", Appres.LngnbNO},
                        {"pl-PL", Appres.LngplPL},
                        {"pt-BR", Appres.LngptBR},
                        {"pt-PT", Appres.LngptPT},
                        {"ru-RU", Appres.LngruRU},
                        {"es-ES", Appres.LngesES},
                        {"sv-SE", Appres.LngsvSE}
                    });
        }

        internal static Project FindProjectByName(DTE2 dte, string name)
        {
            Project found = null;
            if (dte != null)
            {
                var enumprjs = dte.Solution.Projects.GetEnumerator();
                while (enumprjs.MoveNext())
                {
                    if (((Project)enumprjs.Current).Name == name)
                    {
                        found = (Project)enumprjs.Current;
                        break;
                    }
                }
            }
            return found;
        }

        internal static Project GetCurrentProject(DTE2 dte)
        {
            foreach (SelectedItem item in dte.SelectedItems)
            {
                if (item.Project != null) return item.Project;
                if (item.ProjectItem != null) return item.ProjectItem.ContainingProject;
            }
            return null;
        }

        private static ProjectItem GetProjectManifestWp(Project project)
        {
            if (project.ProjectItems == null) return null;

            var subitems = project.ProjectItems.GetEnumerator();
            ProjectItem result = null;
            while (subitems.MoveNext())
            {
                result = GetManifestWp((ProjectItem)subitems.Current);
                if (result != null)
                {
                    break;
                }
            }
            return result;
        }

        internal static Guid GetProjectGuid(IVsSolution solution, Project project)
        {

            IVsHierarchy hierarchy;

            solution.GetProjectOfUniqueName(project.FullName, out hierarchy);

            if (hierarchy != null)
            {
                Guid projectGuid;

                ErrorHandler.Succeeded(
                    hierarchy.GetGuidProperty(
                        VSConstants.VSITEMID_ROOT,
                        (int)__VSHPROPID.VSHPROPID_ProjectIDGuid,
                        out projectGuid));

                if (projectGuid != new Guid())
                {
                    return projectGuid;
                }
            }

            return Guid.Empty;
        }

        internal static bool IsPhoneProject(IVsSolution solution, Project project)
        {
            IVsHierarchy hierarchy;
            solution.GetProjectOfUniqueName(project.FullName, out hierarchy);
            return IsPhoneProject(hierarchy);
        }
        internal static bool IsPhoneProject(IVsHierarchy pHierarchy)
        {
            try
            {
                var aggregatableProject = (IVsAggregatableProject)pHierarchy;
                string projectTypeGuids;
                aggregatableProject.GetAggregateProjectTypeGuids(out projectTypeGuids);
                //windows phone C#/VB Template Project
                if (projectTypeGuids.ToUpper().Contains("{C089C8C0-30E0-4E22-80C0-CE093F111A43}") || projectTypeGuids.Contains("{DB03555F-0C8B-43BE-9FF9-57896B3C5E56}"))
                {
                    return true;
                }
            }
            // ReSharper disable EmptyGeneralCatchClause
            catch { }
            // ReSharper restore EmptyGeneralCatchClause
            return false;
        }

        internal static bool IsVbProject(IVsHierarchy pHierarchy)
        {
            try
            {
                var aggregatableProject = (IVsAggregatableProject)pHierarchy;
                string projectTypeGuids;
                aggregatableProject.GetAggregateProjectTypeGuids(out projectTypeGuids);
                //windows phone C#/VB Template Project
                if (projectTypeGuids.ToUpper().Contains("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}"))
                {
                    return true;
                }
            }
            // ReSharper disable EmptyGeneralCatchClause
            catch { }
            // ReSharper restore EmptyGeneralCatchClause
            return false;
        }

        internal static bool IsCSharpProject(IVsHierarchy pHierarchy)
        {
            try
            {
                var aggregatableProject = (IVsAggregatableProject)pHierarchy;
                string projectTypeGuids;
                aggregatableProject.GetAggregateProjectTypeGuids(out projectTypeGuids);
                //windows phone C#/VB Template Project
                if (projectTypeGuids.ToUpper().Contains("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"))
                {
                    return true;
                }
            }
            // ReSharper disable EmptyGeneralCatchClause
            catch { }
            // ReSharper restore EmptyGeneralCatchClause
            return false;
        }

        internal static bool IsValidProject(IVsHierarchy pHierarchy)
        {
            try
            {
                // ReSharper disable UnusedVariable
                var dummy = (IVsAggregatableProject)pHierarchy;
                // ReSharper restore UnusedVariable
            }
            // ReSharper disable EmptyGeneralCatchClause
            catch
            {
                return false;
            }
            // ReSharper restore EmptyGeneralCatchClause
            return true;
        }




    }
}
